package org.groupg.project.demo;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class JacksonConfigurator {

    // 创建配置好的JSON ObjectMapper
    public static ObjectMapper createJsonMapper() {
        ObjectMapper mapper = new ObjectMapper();
        configureMapper(mapper);
        return mapper;
    }

    // 创建配置好的XML XmlMapper
    public static XmlMapper createXmlMapper() {
        XmlMapper mapper = new XmlMapper();
        configureMapper(mapper);
        configureXmlSpecifics(mapper);
        return mapper;
    }

    // 通用配置
    private static void configureMapper(ObjectMapper mapper) {
        // 基本配置
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        // 注册Java 8日期模块
        mapper.registerModule(new JavaTimeModule());

        // 自定义模块
        SimpleModule customModule = new SimpleModule("CustomModule", Version.unknownVersion());

        // 自定义日期序列化/反序列化
        customModule.addSerializer(LocalDate.class, new LocalDateSerializer());
        customModule.addDeserializer(LocalDate.class, new LocalDateDeserializer());

        // FullName自定义序列化/反序列化
        customModule.addSerializer(FullName.class, new FullNameSerializer());
        customModule.addDeserializer(FullName.class, new FullNameDeserializer());

        // 部门枚举序列化/反序列化
        customModule.addSerializer(Department.class, new DepartmentSerializer());
        customModule.addDeserializer(Department.class, new DepartmentDeserializer());

        // Employee元数据处理
        customModule.addSerializer(Employee.class, new EmployeeSerializer());
        customModule.addDeserializer(Employee.class, new EmployeeDeserializer());

        // 多态技能处理
        customModule.addSerializer(Skill.class, new SkillSerializer());
        customModule.addDeserializer(Skill.class, new SkillDeserializer());

        mapper.registerModule(customModule);
    }

    // XML特定配置
    private static void configureXmlSpecifics(XmlMapper mapper) {
        // 设置XML根元素名称
        mapper.setConfig(mapper.getSerializationConfig()
                .withRootName("EmployeeRecord"));
    }

    // LocalDate序列化器
    static class LocalDateSerializer extends StdSerializer<LocalDate> {
        private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        public LocalDateSerializer() {
            super(LocalDate.class);
        }

        @Override
        public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeString(value.format(FORMATTER));
        }
    }

    // LocalDate反序列化器
    static class LocalDateDeserializer extends StdDeserializer<LocalDate> {
        private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        public LocalDateDeserializer() {
            super(LocalDate.class);
        }

        @Override
        public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            return LocalDate.parse(p.getText(), FORMATTER);
        }
    }

    // FullName序列化器
    static class FullNameSerializer extends StdSerializer<FullName> {
        public FullNameSerializer() {
            super(FullName.class);
        }

        @Override
        public void serialize(FullName value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeString(value.getFirstName() + " " + value.getLastName());
        }
    }

    // FullName反序列化器
    static class FullNameDeserializer extends StdDeserializer<FullName> {
        public FullNameDeserializer() {
            super(FullName.class);
        }

        @Override
        public FullName deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            String fullName = p.getText();
            String[] parts = fullName.split(" ");
            return new FullName(parts[0], parts.length > 1 ? parts[1] : "");
        }
    }

    // Department序列化器
    static class DepartmentSerializer extends StdSerializer<Department> {
        private static final Map<Department, String> MAPPING = new EnumMap<>(Department.class);

        static {
            MAPPING.put(Department.IT, "IT");
            MAPPING.put(Department.HR, "HR");
            MAPPING.put(Department.FINANCE, "Finance");
        }

        public DepartmentSerializer() {
            super(Department.class);
        }

        @Override
        public void serialize(Department value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeString(MAPPING.get(value));
        }
    }

    // Department反序列化器
    static class DepartmentDeserializer extends StdDeserializer<Department> {
        private static final Map<String, Department> MAPPING = new HashMap<>();

        static {
            MAPPING.put("IT", Department.IT);
            MAPPING.put("HR", Department.HR);
            MAPPING.put("Finance", Department.FINANCE);
            MAPPING.put("FINANCE", Department.FINANCE);
        }

        public DepartmentDeserializer() {
            super(Department.class);
        }

        @Override
        public Department deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            return MAPPING.getOrDefault(p.getText(), null);
        }
    }

    // Employee序列化器
    static class EmployeeSerializer extends StdSerializer<Employee> {
        public EmployeeSerializer() {
            super(Employee.class);
        }

        @Override
        public void serialize(Employee value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeStartObject();

            // 处理XML属性
            if (gen instanceof ToXmlGenerator) {
                // 对于XML，将employeeCode作为属性
                ((ToXmlGenerator) gen).setNextIsAttribute(true);
                gen.writeFieldName("employeeCode");
                gen.writeString(value.getEmployeeCode());
                ((ToXmlGenerator) gen).setNextIsAttribute(false);
            } else {
                // 对于JSON，使用"empId"作为字段名
                gen.writeStringField("empId", value.getEmployeeCode());
            }

            // 序列化字段
            gen.writeObjectField("fullName", value.getFullName());
            gen.writeObjectField("employmentDate", value.getEmploymentDate());
            gen.writeNumberField("monthlySalary", value.getSalary());
            gen.writeObjectField("department", value.getDepartment());

            // 序列化技能列表
            gen.writeArrayFieldStart("skills");
            for (Skill skill : value.getSkills()) {
                gen.writeObject(skill);
            }
            gen.writeEndArray();

            // 元数据作为顶级字段
            for (Map.Entry<String, Object> entry : value.getMetadata().entrySet()) {
                gen.writeFieldName(entry.getKey());
                gen.writeObject(entry.getValue());
            }

            gen.writeEndObject();
        }
    }

    // Employee反序列化器
    static class EmployeeDeserializer extends StdDeserializer<Employee> {
        public EmployeeDeserializer() {
            super(Employee.class);
        }

        @Override
        public Employee deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            JsonNode node = p.getCodec().readTree(p);

            // 提取字段
            String empId = node.has("empId") ? node.get("empId").asText() :
                    node.has("employeeCode") ? node.get("employeeCode").asText() : null;

            double salary = node.has("monthlySalary") ? node.get("monthlySalary").asDouble() :
                    node.has("salary") ? node.get("salary").asDouble() : 0.0;

            // 创建Employee对象
            Employee emp = new Employee(empId, salary);

            // 设置其他字段
            if (node.has("fullName")) {
                emp.setFullName(ctxt.readTreeAsValue(node.get("fullName"), FullName.class));
            }

            if (node.has("employmentDate")) {
                emp.setEmploymentDate(ctxt.readTreeAsValue(node.get("employmentDate"), LocalDate.class));
            }

            if (node.has("department")) {
                emp.setDepartment(ctxt.readTreeAsValue(node.get("department"), Department.class));
            }

            if (node.has("skills")) {
                JsonNode skillsNode = node.get("skills");
                if (skillsNode.isArray()) {
                    for (JsonNode skillNode : skillsNode) {
                        Skill skill = ctxt.readTreeAsValue(skillNode, Skill.class);
                        if (skill != null) emp.addSkill(skill);
                    }
                }
            }

            // 提取元数据
            Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
            while (fields.hasNext()) {
                Map.Entry<String, JsonNode> entry = fields.next();
                String field = entry.getKey();
                if (!field.equals("empId") && !field.equals("employeeCode") &&
                        !field.equals("fullName") && !field.equals("employmentDate") &&
                        !field.equals("monthlySalary") && !field.equals("salary") &&
                        !field.equals("department") && !field.equals("skills")) {
                    JsonNode valueNode = entry.getValue();
                    Object value;
                    if (valueNode.isBoolean()) {
                        value = valueNode.asBoolean();
                    } else if (valueNode.isInt()) {
                        value = valueNode.asInt();
                    } else if (valueNode.isDouble()) {
                        value = valueNode.asDouble();
                    } else {
                        value = valueNode.asText();
                    }
                    emp.addMetadata(field, value);
                }
            }

            return emp;
        }
    }

    // Skill序列化器
    static class SkillSerializer extends StdSerializer<Skill> {
        public SkillSerializer() {
            super(Skill.class);
        }

        @Override
        public void serialize(Skill value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeStartObject();

            // 添加类型标识
            if (value instanceof TechnicalSkill) {
                gen.writeStringField("type", "technical");
                TechnicalSkill ts = (TechnicalSkill) value;
                gen.writeStringField("programming_language", ts.getLanguage());
                gen.writeNumberField("level", ts.getLevel());
            } else if (value instanceof ManagementSkill) {
                gen.writeStringField("type", "management");
                ManagementSkill ms = (ManagementSkill) value;
                gen.writeStringField("domain", ms.getDomain());
                gen.writeStringField("cert", ms.getCertification());
            }

            gen.writeEndObject();
        }
    }

    // Skill反序列化器
    static class SkillDeserializer extends StdDeserializer<Skill> {
        public SkillDeserializer() {
            super(Skill.class);
        }

        @Override
        public Skill deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            JsonNode node = p.getCodec().readTree(p);

            String type = node.has("type") ? node.get("type").asText() : null;
            if ("technical".equals(type)) {
                TechnicalSkill ts = new TechnicalSkill();
                if (node.has("programming_language")) ts.setLanguage(node.get("programming_language").asText());
                if (node.has("language")) ts.setLanguage(node.get("language").asText());
                if (node.has("level")) ts.setLevel(node.get("level").asInt());
                return ts;
            } else if ("management".equals(type)) {
                ManagementSkill ms = new ManagementSkill();
                if (node.has("domain")) ms.setDomain(node.get("domain").asText());
                if (node.has("cert")) ms.setCertification(node.get("cert").asText());
                if (node.has("certification")) ms.setCertification(node.get("certification").asText());
                return ms;
            }

            return null;
        }
    }
}